﻿' ----------------------------------------------------------------------------------
' Microsoft Developer & Platform Evangelism
' 
' Copyright (c) Microsoft Corporation. All rights reserved.
' 
' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ----------------------------------------------------------------------------------
' The example companies, organizations, products, domain names,
' e-mail addresses, logos, people, places, and events depicted
' herein are fictitious.  No association with any real company,
' organization, product, domain name, email address, logo, person,
' places, or events is intended or should be inferred.
' ----------------------------------------------------------------------------------

Imports System.Globalization
Imports System.IO
Imports System.Net
Imports System.ServiceModel.Activation
Imports Microsoft.WindowsAzure
Imports Microsoft.WindowsAzure.StorageClient
Imports WindowsPhone.Recipes.Push.Messages

Namespace Infrastructure

    Public Module Extensions
        Private Const ErrorResponse As String = "<?xml version=""1.0"" encoding=""utf-8"" standalone=""yes"" ?><error {0}><code>{1}</code><message xml:lang=""en-US"">{2}</message></error>"
        Private Const DataServiceNamespace As String = "xmlns=""http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"""

        <System.Runtime.CompilerServices.Extension()> _
        Public Function ToModel(ByVal blobItem As IListBlobItem, ByVal containerName As String, ByVal accountName As String) As Models.CloudBlob
            Dim blob = TryCast(blobItem, CloudBlob)
            Dim sas = blob.GetSharedAccessSignature(New SharedAccessPolicy(), "readonly")
            Dim uriBuilder = New UriBuilder(blob.Uri) With {.Query = sas.TrimStart("?"c)}
            Dim blobUri = uriBuilder.Uri
            Dim blobName = blobUri.LocalPath

            ' When using the Storage Emulator the first segment is the dev account, not the container.
            Dim devaccount = CloudStorageAccount.DevelopmentStorageAccount.Credentials.AccountName
            If accountName.Equals(devaccount, StringComparison.OrdinalIgnoreCase) AndAlso blobName.StartsWith(String.Format(CultureInfo.InvariantCulture, "/{0}", devaccount), StringComparison.OrdinalIgnoreCase) Then
                blobName = blobName.Remove(0, devaccount.Length + 1)
            End If

            Return New Models.CloudBlob With {.Name = blobName.Remove(0, containerName.Length + 1).TrimStart("/"c), .Uri = blobUri}
            ' Remove container name.
        End Function

        <CLSCompliant(False)>
        <System.Runtime.CompilerServices.Extension()> _
        Public Function SendAndHandleErrors(ByVal message As PushNotificationMessage, ByVal uri As Uri) As MessageSendResultLight
            Dim result As MessageSendResultLight
            Try
                Dim sendResult = message.Send(uri)
                result = If(sendResult.NotificationStatus = NotificationStatus.Received, New MessageSendResultLight With {.Status = MessageSendResultLight.Success}, New MessageSendResultLight With {.Status = MessageSendResultLight.Error, .Description = "The notification was not received by the device."})
            Catch exception As Exception
                result = New MessageSendResultLight With {.Status = MessageSendResultLight.Error, .Description = exception.Message}
            End Try

            Return result
        End Function

        <System.Runtime.CompilerServices.Extension> _
        Public Function MenuItem(ByVal helper As HtmlHelper, ByVal linkText As String, ByVal actionName As String, ByVal controllerName As String) As MvcHtmlString
            Dim li = New TagBuilder("li")
            Dim routeData = helper.ViewContext.RouteData
            Dim currentAction = routeData.GetRequiredString("action")
            Dim currentController = routeData.GetRequiredString("controller")
            If String.Equals(currentAction, actionName, StringComparison.OrdinalIgnoreCase) AndAlso String.Equals(currentController, controllerName, StringComparison.OrdinalIgnoreCase) Then
                li.AddCssClass("selected")
            End If

            li.InnerHtml = helper.ActionLink(linkText, actionName, controllerName).ToHtmlString()
            Return MvcHtmlString.Create(li.ToString())
        End Function

        <System.Runtime.CompilerServices.Extension()> _
        Public Sub EndWithDataServiceError(ByVal response As HttpResponse, ByVal code As Integer, ByVal [error] As String, ByVal detail As String)
            response.Clear()
            response.ContentType = HttpConstants.MimeApplicationAtomXml
            response.StatusCode = code
            response.StatusDescription = [error]
            response.Write(String.Format(CultureInfo.InvariantCulture, ErrorResponse, DataServiceNamespace, [error], detail))
            response.Flush()
            response.End()
            response.Clear()
        End Sub

        <System.Runtime.CompilerServices.Extension()> _
        Public Sub CopyRequestHeadersTo(ByVal sourceRequest As HttpRequest, ByVal destinationRequest As WebRequest)
            destinationRequest.ContentType = sourceRequest.ContentType

            Dim finalHttpWebRequest = TryCast(destinationRequest, HttpWebRequest)
            If finalHttpWebRequest IsNot Nothing Then
                Dim connection = sourceRequest.Headers("Connection")
                finalHttpWebRequest.KeepAlive = If((Not String.IsNullOrEmpty(connection)) AndAlso connection.Equals("Close", StringComparison.OrdinalIgnoreCase), False, True)
                finalHttpWebRequest.Accept = HttpConstants.MimeApplicationAtomXml
                finalHttpWebRequest.Referer = sourceRequest.Headers("Referer")
                finalHttpWebRequest.UserAgent = sourceRequest.Headers("User-Agent")
            End If

            Dim excludeHeaders() As String = {"Connection", "Accept", "User-Agent", "Host", "Authorization", "AuthToken", "x-ms-date", "Content-Length", "Content-Type", "Referer"}

            For Each header In sourceRequest.Headers.AllKeys
                If Not excludeHeaders.Contains(header) Then
                    destinationRequest.Headers.Add(header, sourceRequest.Headers(header))
                End If
            Next header
        End Sub

        <System.Runtime.CompilerServices.Extension()> _
        Public Function ExtractBodyString(ByVal webResponse As WebResponse) As String
            Using stream = webResponse.GetResponseStream()
                Return New StreamReader(stream).ReadToEnd()
            End Using
        End Function

        <System.Runtime.CompilerServices.Extension()> _
        Public Sub CopyResponseHeadersTo(ByVal sourceResponse As WebResponse, ByVal destinationResponse As HttpResponse, ByVal contentType As String)
            destinationResponse.ContentType = contentType

            Dim httpWebResponse = TryCast(sourceResponse, HttpWebResponse)
            If httpWebResponse IsNot Nothing Then
                destinationResponse.StatusCode = CInt(Fix(httpWebResponse.StatusCode))
                destinationResponse.StatusDescription = httpWebResponse.StatusDescription
            End If

            Dim excludeHeaders() As String = {"Content-Type", "Transfer-Encoding"}
            For Each header In sourceResponse.Headers.AllKeys
                If Not excludeHeaders.Contains(header) Then
                    destinationResponse.Headers.Add(header, sourceResponse.Headers(header))
                End If
            Next header
        End Sub

        <System.Runtime.CompilerServices.Extension()> _
        Public Sub AddWcfServiceRoute(ByVal routes As RouteCollection, ByVal dataServiceType As Type, ByVal prefix As String)
            routes.Add(New ServiceRoute(prefix, New AutomaticFormatServiceHostFactory(), dataServiceType))
        End Sub

        <System.Runtime.CompilerServices.Extension()> _
        Public Sub AddWcfServiceRoute(Of TService)(ByVal routes As RouteCollection, ByVal prefix As String)
            AddWcfServiceRoute(routes, GetType(TService), prefix)
        End Sub
    End Module
End Namespace